home *** CD-ROM | disk | FTP | other *** search
/ Aminet 13 / Aminet 13 - August 1996.iso / Aminet / comm / fido / MM_SMFEDcode.lha / MM / Rexx / MM_SMFEDcode.rexx < prev    next >
OS/2 REXX Batch file  |  1996-05-24  |  24KB  |  1,169 lines

  1. /*
  2.  
  3.                       $VER: MM_SMFEDcode 0.81  (24.05.96)
  4.                           (was renamed from MM_UUout)
  5.  
  6.                            (C) 1995/96 Robert Hofmann
  7.  
  8. */
  9.  
  10. parse arg args
  11.  
  12. options cache
  13. options failat 99
  14. options results
  15.  
  16. signal on break_c
  17. signal on break_d
  18. signal on break_e
  19. signal on break_f
  20. signal on halt
  21. signal on ioerr
  22. signal on syntax
  23.  
  24. address 'MAILMANAGER'
  25.  
  26.  
  27. Main:
  28.  
  29.     call Init
  30.     call Header
  31.     call Parse_Args(args)
  32.     call Read_Cfg
  33.  
  34.     if system.arg.gui    then Show
  35.  
  36.     select
  37.         when system.arg.encode    then call Encode
  38.         when system.arg.decode    then call Decode(system.arg.area, system.arg.msg)
  39.  
  40.         otherwise signal Usage
  41.     end
  42.  
  43. call Quit(0, 'All done.')
  44. exit
  45.  
  46.  
  47. Add_Text: procedure Expose msg.
  48.  
  49.     parse arg line
  50.  
  51.     MM_AddToStem 'msg.text' 'line'
  52.  
  53. return
  54.  
  55.  
  56. break_c:; break_d:; break_e:; break_f:; halt:
  57.     return_code        =    5
  58.     error_line    = 0
  59.     error_msg            = 'Execution halted!!!'
  60.     rc                        = 0
  61. signal Exit
  62.  
  63.  
  64. Check_Pattern: procedure Expose result
  65.  
  66.     arg pattern, string.0
  67.  
  68.     string.count    = 1
  69.     result.                = 0
  70.  
  71.     MM_SearchInStem 'string' 'result' pattern 'STR'
  72.  
  73.     result                = result.0
  74. return result.count>0
  75.  
  76.  
  77. Command: procedure Expose system.
  78.  
  79.     parse arg cmd, noreq
  80.  
  81.     address command cmd; ret = rc
  82.  
  83.     if noreq~=1 & ret>0 then
  84.         do
  85.             call Log('*** WARNING: Command "'cmd'" returned' ret'.')
  86.  
  87.             if system.arg.gui then call Request_Choice('\c\n* * *   W A R N I N G   * * *\n\n"' ||,
  88.                 cmd'"\n\nreturned' ret'!\n', '*  _OK  ', '_')
  89.         end
  90.  
  91. return rc
  92.  
  93.  
  94. Decode: procedure Expose system.
  95.  
  96.   arg area, nr
  97.  
  98.     deldir = 'c:delete >NIL:' system.tmpdir 'all quiet noreq force'
  99.     call Command(deldir, 1)
  100.  
  101.     if ~makedir(strip(system.tmpdir, 't', '/ ')) then call Quit(31, 'Unable to create tmpdir "'system.tmpdir'"!!!')
  102.  
  103.     call Search_Encoded_Files(area, nr, 0, 0)
  104.     call delete(system.tmpfile)
  105.     call Command('c:list >'system.tmpfile system.tmpdir 'lformat "%n %l"')
  106.  
  107.     MM_ReadStem system.tmpfile 'tmp'
  108.     call delete(system.tmpfile)
  109.  
  110.     file.    = 0
  111.     len.    = 0
  112.     note    = 'From:' msg.from '%' msg.fromaddr'; Area:' area
  113.  
  114.     do n=0 to tmp.count-1
  115.         parse var tmp.n    fl ln .
  116.  
  117.     file.max    = max(file.max, length(fl)+2)
  118.         file.n        = fl
  119.         len.max        = max(len.max,    length(ln))
  120.         len.n            = ln
  121.  
  122.         from            = system.tmpdir  || fl
  123.         to                = system.prg.dir || fl
  124.  
  125.         MM_SetFileNote    from 'note'
  126.  
  127.         if exists(to)    then MM_MoveFile to to
  128.  
  129.         MM_MoveFile            from to
  130.  
  131.         call Log('Decoded:' fl ln 'bytes')
  132.     end
  133.  
  134.     file.count    = tmp.count
  135.     len.count        = tmp.count
  136.  
  137.     call Command(deldir)
  138.  
  139.     if system.arg.gui then
  140.         do
  141.             if file.count>0 then
  142.                 do
  143.                     if n>1 then    tmp    = 's were'
  144.                     else                tmp    = ' was'
  145.  
  146.                     text    = '\c\nThe following file'tmp 'decoded from\narea' area', msg #'nr 'to "'system.prg.dir'":\n\n'
  147.                 end
  148.             else text = '\c\nThere were no uuencoded files in this msg!!!\n'
  149.  
  150.             do n=0 to file.count-1
  151.                 text    = text'\1'left(file.n, file.max) || right(len.n, len.max) 'bytes\0\n'
  152.             end
  153.  
  154.           call Request_Choice(text, '*   _OK   ', '_')
  155.         end
  156.  
  157.     if system.ok then
  158.         do
  159.             flags    = 'READ'
  160.  
  161.             if system.msg.count>2 then Hide
  162.  
  163.             do n=0 to system.msg.count-1
  164.                 MM_EditMsgFlags area system.msg.n 'flags'
  165.             end
  166.  
  167.             Show
  168.         end
  169.  
  170. return
  171.  
  172.  
  173. Decode_File: procedure Expose system.
  174.  
  175.     parse arg mode, file
  176.  
  177.     olddir    = pragma('d', system.tmpdir)
  178.  
  179.     call Log('Decoding' mode'-encoded file...',, 4)
  180.     ret    = Command(system.cmd.mode.decode)
  181.     call pragma('d', olddir)
  182.  
  183. return ret
  184.  
  185.  
  186. Encode: procedure Expose system.
  187.  
  188.     call Get_Datas
  189.     call Send_File(system.arg.mode)
  190.  
  191. return
  192.  
  193.  
  194. Exit:
  195.  
  196.     select
  197.         when return_code>=40 then error = 'INTERNAL-ERROR:'
  198.         when return_code>=30 then error = 'IO-ERROR:'
  199.         when return_code>=20 then error = 'ERROR:'
  200.         when return_code>=10 then error = 'WARNING:'
  201.         when return_code>=5  then error = 'INFO:'
  202.         otherwise                                    error = ''
  203.     end
  204.  
  205.     if system.arg.gui & return_code>5    then
  206.         do
  207.             tmp    = center(error_msg, max(length(error_msg), 40))
  208.             call Request_Choice('\c\n'error'\n\n\1'tmp'\0\n', '*  _OK  ', '_')
  209.         end
  210.  
  211.   call Log(,, 3)
  212.     call Log('***' strip(error error_msg) '***', '+')
  213.     call Log(,'\',, 3)
  214.  
  215.     call setclip('MM_LogPre', system.mm.logpre)
  216.  
  217. exit return_code
  218.  
  219.  
  220. Expand_Path: procedure
  221.  
  222.     parse arg path
  223.  
  224.     if pos(':', path)+pos('/', path)=0 then path = path(pragma('d')) || path
  225.  
  226. return path
  227.  
  228.  
  229. Get_Addr: procedure Expose msg. system.
  230.  
  231.     if msg.area.data.type~='MAIL' then return ''
  232.  
  233.     parse arg text
  234.  
  235.     ok  = 0
  236.     tmp    = ''
  237.  
  238.     do while ok=0
  239.         tmp = Request_String(text, tmp, 1)
  240.  
  241.         parse var tmp z ':' nt '/' nd '.' p '@' d '.' .
  242.  
  243.         ok        = datatype(z, 'N') & datatype(nt, 'N') & datatype(nd, 'N') & datatype(p, 'N') &,
  244.                         datatype(d, 'A') & upper(d)=msg.domain
  245.         addr    = tmp
  246.     end
  247.  
  248. return addr
  249.  
  250.  
  251. Get_Arg: procedure Expose args system.
  252.  
  253.   arg keyword, mode, old
  254.  
  255.     uargs    = upper(args)
  256.     p            = find(uargs, keyword)
  257.  
  258.     if p=0    then
  259.         do
  260.             p = pos(' 'keyword'=', ' 'uargs)
  261.  
  262.             if p>0 then    args    = overlay(' ', args, p+length(keyword))
  263.  
  264.       p = find(upper(args), keyword)
  265.         end
  266.  
  267.     system.cmdopt.keyword    = p>0
  268.  
  269.     select
  270.         when mode=0    then
  271.             if p>0 then
  272.                 do
  273.                     ret        = 1
  274.                     args    = delword(args, p, 1)
  275.                 end
  276.             else ret    = old
  277.  
  278.         when mode=1 then
  279.             if p>0 then
  280.                 do
  281.                     left    = subword(args, 1, p-1)
  282.                     rest    = subword(args, p+1)
  283.  
  284.                     if left(rest, 1)='"' then    parse var rest . '"'    ret '"'    rest
  285.                     else                                            parse var rest                ret            rest
  286.  
  287.                     args    = strip(left strip(rest))
  288.                 end
  289.             else ret    = old
  290.  
  291.         when mode=2 then
  292.             do
  293.                 if left(args, 1)='"'    then    parse var args . '"'    ret '"'    args
  294.                 else                                                parse var args                ret         args
  295.  
  296.                 if strip(ret)=''            then    ret = old
  297.             end
  298.  
  299.         otherwise exit 99
  300.     end
  301.  
  302.     args    = strip(args)
  303.     ret        = strip(ret, 'b', '" ')
  304.  
  305. return ret
  306.  
  307.  
  308. Get_Datas: procedure Expose msg. system.
  309.  
  310.   MM_GetAddrs                    'system.addr'
  311.     system.addresses  = ''
  312.  
  313.     do n=0 to system.addr.count-1
  314.         system.addresses = system.addresses system.addr.n
  315.     end
  316.  
  317.     upper system.addresses
  318.  
  319.     msg.send    = system.arg.file
  320.     tmp                = 'AREA FLAGS FROM FROMADDR SUBJ TO TOADDR'
  321.  
  322.     do while tmp~=''
  323.         parse var tmp field tmp
  324.  
  325.         msg.field    = '*'
  326.         if system.arg.field~=''    then msg.field    = system.arg.field
  327.     end
  328.  
  329.     if system.arg.gui    then
  330.         do
  331.             call Log('Asking for datas...',, 4)
  332.  
  333.             system.arg.mode    = Request_Choice('What encoding-methode do you want to use?',,
  334.                                                 '_FS-encode|_MIME|_Abort|*_UU-encode', 'FS MIME _ UU')
  335.  
  336.             if system.arg.mode=''    then call Quit(5, 'Aborted by user!')
  337.         end
  338.  
  339.     if system.arg.gui then
  340.         do
  341.             if msg.area='*'    then
  342.                 do
  343.                     MM_AreaReq 'msg.area'
  344.                     if RC~=0    then call Quit(5, 'Aborted by user!')
  345.                 end
  346.  
  347.             do while msg.send='' | ~exists(msg.send)
  348.                 msg.send = path(pragma('d'))
  349.  
  350.                 MM_FileReq 'msg.send'
  351.                 if RC=1    then call Quit(5, 'Aborted by user!')
  352.             end
  353.         end
  354.  
  355.     if ~exists(msg.send)    then call Quit(11, 'Unable to locate "'msg.send'"!')
  356.  
  357.     if system.arg.gui & msg.area=''    then
  358.         do
  359.             MM_AreaReq 'msg.area'
  360.             if RC=1    then call Quit(5, 'Aborted by user!')
  361.         end
  362.  
  363.     MM_GetAreaInfo msg.area 'msg.area.data'
  364.     if RC~=0 then call Quit(11, 'Unknown area "'msg.area'"!')
  365.     msg.domain = Get_Domain(msg.area.data.addr)
  366.  
  367.     if system.arg.gui then
  368.         do
  369.             ret    = Request_Choice('Do you also want to send an introduction-msg?', ' _Use file |_Write now|*  _NO  ', '1 2 0')
  370.  
  371.             select
  372.                 when ret=1    then
  373.                     do
  374.                         system.arg.infofile    = 'ff'x
  375.  
  376.                         do while ~exists(system.arg.infofile)
  377.                             system.arg.infofile = path(system.mm.tempdir)
  378.  
  379.                             MM_FileReq 'system.arg.infofile'
  380.                             if RC=1    then call Quit(5, 'Aborted by user!')
  381.                         end
  382.  
  383.                         system.arg.delinfofile    = Request_Choice('\c\nDelete \1'system.arg.infofile'\0 after posting?',,
  384.                                                                             ' _YES  |*  _NO  ', '1 0')
  385.                     end
  386.  
  387.                 when ret=2 then
  388.                     do
  389.                         system.arg.infofile            = system.tmpfile'.inf'
  390.                         system.arg.delinfofile    = 1
  391.  
  392.                         call Command(replace(system.mm.editor, system.arg.infofile, '%s'))
  393.                     end
  394.  
  395.                 otherwise nop
  396.             end
  397.         end
  398.  
  399.     system.is_mail    = msg.area.data.type='MAIL'
  400.     system.is_echo    = ~system.is_mail
  401.  
  402.     if msg.toaddr='*' then
  403.         if system.is_mail then
  404.             if system.arg.gui then msg.toaddr = Get_Addr('To-Address')
  405.             else call Quit(11, 'To-address missing!')
  406.         else drop msg.toaddr
  407.  
  408.     if msg.to='*'             then
  409.         if system.is_mail    then    msg.to    = Get_Name(msg.toaddr)
  410.         else                            msg.to    = 'All'
  411.  
  412.     if system.arg.gui    then    msg.to    = Request_String('To-name', msg.to, 1)
  413.  
  414.     if msg.fromaddr='*' & system.is_mail then
  415.       if system.arg.gui then
  416.         do
  417.                 MM_GetAddrs 'tmp'
  418.  
  419.                 req.    = 0
  420.  
  421.                 do n=0 to tmp.count-1
  422.                     if Get_Domain(tmp.n)=msg.domain then MM_AddToStem 'req' 'tmp.'n
  423.                 end
  424.  
  425.                 select
  426.                     when req.count=0    then    call Quit(20, 'No valid source-#ADDRESS or #AKA for' system.fromaddr'!!!')
  427.  
  428.                     when req.count=1    then    msg.fromaddr    = req.0
  429.  
  430.                     otherwise
  431.                         do
  432.                       RC         = -99
  433.                             tmp.    = ''
  434.  
  435.                             MM_SingleSelReq 'req' 'tmp' '"Address"' 'STR'
  436.                             if RC=1    then call Quit(5, 'Aborted by user!')
  437.  
  438.                             if tmp.0~=''then  msg.fromaddr = tmp.0
  439.                         end
  440.                 end
  441.             end
  442.         else    msg.fromaddr = msg.area.data.addr
  443.     else        msg.fromaddr = msg.area.data.addr
  444.  
  445.     if msg.from='*'        then    tmp    = Get_Name(msg.fromaddr)
  446.     else                                        tmp    = msg.from
  447.  
  448.     if system.arg.gui    then    tmp = Request_String('From-Name', tmp, 0)
  449.  
  450.     if tmp='' then drop msg.from
  451.     else msg.from = tmp
  452.  
  453.     if msg.subj='*' then
  454.         do
  455.             sfile = msg.send
  456.             p            = lastpos('/', sfile)
  457.             if p>0 then sfile = substr(sfile, p+1)
  458.             p            = lastpos(':', sfile)
  459.             if p>0 then sfile = substr(sfile, p+1)
  460.             tmp        = ''
  461.  
  462.             if system.arg.gui then sfile    = Request_String('Subject', sfile, 1)
  463.  
  464.             msg.subj    = sfile
  465.         end
  466.  
  467.      if system.arg.gui & msg.flags='*' then
  468.         do
  469.             msg.flags    = ''
  470.  
  471.             if system.is_mail then
  472.                 do
  473.                   req.0            = 'CRASH'
  474.                     req.1            = 'HOLD'
  475.                     req.2            = 'KILL'
  476.                     req.3            = 'RRR'
  477.                     req.count    = 4
  478.                 end
  479.             else
  480.                 do
  481.                     req.0            = 'KILL'
  482.                     req.count    = 1
  483.                 end
  484.  
  485.             tmp.            = 0
  486.  
  487.             MM_MultiSelReq 'req' 'tmp' '"Flags"' 'STR'
  488.             if RC=1    & system.mm.release>=449 then call Quit(5, 'Aborted by user!')
  489.  
  490.             do n=0 to tmp.count-1
  491.                 msg.flags    = msg.flags tmp.n
  492.             end
  493.         end
  494.  
  495. return
  496.  
  497.  
  498. Get_Domain: procedure
  499.  
  500.     arg . '@' dmn '.' .
  501. return dmn
  502.  
  503.  
  504. Get_Encoded_File: procedure Expose msg. system.
  505.  
  506.     parse arg mode, area, msgnr, start, ende, open, offs
  507.  
  508.     cont.    = 0
  509.  
  510.     if start=-1    then
  511.         do
  512.             start            = 0
  513.             cont.prev    = 1
  514.         end
  515.  
  516.     if ende=-1    then
  517.         do
  518.             ende            = msg.text.count-1
  519.             cont.next    = 1
  520.         end
  521.  
  522.     if cont.prev    then
  523.         if Search_Encoded(mode, 'BEGIN') then
  524.             if result.0<ende then call Quit(20, 'Could not find end of encoded file!')
  525.  
  526.     if open then
  527.         do
  528.             if ~open(out, system.tmpfile, 'w') then call Quit(30, 'Unable to open "'system.tmpfile'" for write!')
  529.  
  530.             tmp                    = start+offs+1
  531.             msg.enclen    = length(msg.text.tmp)
  532.         end
  533.  
  534.     if ~cont.prev then
  535.         do
  536.             if mode='MIME' then
  537.                 do n=start-2 to start
  538.                     call writeln(out, msg.text.n)
  539.                 end
  540.             else call Write_Line(start, 0)
  541.  
  542.             msg.text.start    = '*** DONE ***'
  543.         end
  544.     else call Write_Line(start, 1)
  545.  
  546.     fail = 0
  547.     last = 0
  548.  
  549.     do n=start+1 to ende-1
  550.         check    = (cont.prev & cont.next) | (n>start+offs & n<ende-2) | (cont.next & n>start+2) | (cont.prev & n<ende-2)
  551.         ret        = Write_Line(n, check)
  552.         fail    = fail+~ret
  553.  
  554.         if ret then
  555.             do
  556.                 fail    = 0
  557.                 last    = n
  558.             end
  559.  
  560.         if fail~=20    then iterate
  561.  
  562.         cont.next    = 0
  563.         ende            = last+1
  564.  
  565.         leave
  566.     end
  567.  
  568.     call Write_Line(ende, cont.next)
  569.     msg.text.ende    = msg.text.start
  570.  
  571.     tmp    = ende+1
  572.     if mode='UU' & upper(left(msg.text.tmp, 4))='SIZE' then    call writeln(out, msg.text.tmp)
  573.  
  574.     if cont.next then
  575.         do
  576.             msgnr    = msgnr+1
  577.  
  578.             if msgnr>system.ainfo.himsg then
  579.                 if mode~='MIME'                        then    call Quit(20, 'Could not find end of encoded file!')
  580.         else                                                        call Write_Line(last+1, 0)
  581.             else
  582.                 do
  583.                     call Read_Msg(area, msgnr, 'Could not find end of encoded file!')
  584.                     call Search_Encoded(mode, 'END')
  585.  
  586.               if result.count=0 then    ende    = -1
  587.                     else                                        ende    = result.0
  588.  
  589.               msgnr    = Get_Encoded_File(mode, area, msgnr, -1, ende, 0, 2)
  590.                 end
  591.         end
  592.  
  593.     if open then    call close(out)
  594.  
  595. return msgnr
  596.  
  597.  
  598. Get_Name: procedure Expose msg. system.
  599.  
  600.     parse arg address
  601.  
  602.   MM_GetNodelistNode address 'tmp'
  603.  
  604.     if rc>0 then
  605.         if find(system.addresses, upper(address))>0 then
  606.             if system.mm.release<429    then do; MM_GetSysop 'ret'; end
  607.             else    ret    = msg.area.data.alias
  608.         else        ret = 'Sysop'
  609.     else            ret = tmp.sysop
  610.  
  611. return ret
  612.  
  613.  
  614. Get_Version: procedure
  615.  
  616.     parse arg mode
  617.  
  618.     parse value sourceline(3-mode) with . . ver .
  619.     parse var ver tst 'ß' .
  620.  
  621.     if ~datatype(strip(tst, 'b', '/ce '), 'N') then
  622.         if ~mode then ver = Get_Version(1)
  623.         else exit 99
  624.  
  625. return ver
  626.  
  627.  
  628. Header:
  629.  
  630.     call Log(,'/',, 3)
  631.     call Log('***' system.prg.id '***', '+')
  632.     call Log(system.prg.cr)
  633.     call Log(,, 3)
  634.  
  635. return
  636.  
  637.  
  638. Include_Lib: procedure
  639.  
  640.     parse arg lib, prio
  641.     if right(upper(lib), 8)~='.LIBRARY' then lib=lib'.library'
  642.     if prio='' then prio=0
  643.  
  644.     if ~show('l', lib) then
  645.         if ~addlib(lib, prio, -30, 0) then
  646.             do
  647.                 say '*** ERROR: Could not open' lib'!!! ***'
  648.                 exit 10
  649.             end
  650. return
  651.  
  652.  
  653. Init:
  654.  
  655.     system.                                    = 0
  656.  
  657.     MM_GetTaskPri                        'system.taskpri'
  658.     call                                        pragma('p', system.taskpri)
  659.  
  660.     system.prg.name                    = 'MM_SMFEDcode'
  661.     system.prg.version            = Get_Version(0)
  662.     system.prg.id                        = system.prg.name 'v'system.prg.version
  663.     system.prg.cr                        = '(C) 1995/96 Robert Hofmann'
  664.     system.prg.cfg                    = 'MM:Config/'system.prg.name'.cfg'
  665.     system.fs.ptrn.begin        =    '"!start #?"'
  666.     system.fs.ptrn.end            = '"!end #[0-9] #?"'
  667.     system.fs.offs.begin        = 1
  668.     system.mime.ptrn.begin  = '"Content-transfer-encoding:#?base64#?"'
  669.     system.mime.ptrn.end         = '"#?="'
  670.     system.mime.offs.begin    = 1
  671.     system.uu.ptrn.begin        =    '"begin #[0-9] #?"'
  672.     system.uu.ptrn.end            = 'end'
  673.     system.uu.offs.begin        = 1
  674.     system.mm.logpre                 = getclip('MM_LogPre')
  675.     system.prg.logpre                = system.mm.logpre'|'
  676.     call                                            setclip('MM_LogPre', system.prg.logpre)
  677.     system.cmdopts                    = 'DECODE/S,ENCODE/S,GUI/S,AREA/K,MSG/K,FILE/K,FLAGS/K,FROM/K,' ||,
  678.                                                         'FROMADDR/K,ORIGIN/K,SUBJ/K,TO/K,TOADDR/K,INFOFILE/K,MODE/K,'    ||,
  679.                                                         'DELINFOFILE/S,MAXSIZE/K/N'
  680.  
  681.     MM_Version                                'system.mm'
  682.     MM_GetCfgPaths                        'system.mm'
  683.  
  684.     call Include_Lib('rexxsupport')
  685. return
  686.  
  687.  
  688. IOerr:
  689.     return_code        = 20
  690.     error_line    = sigl
  691.     error_msg            = 'IO-error' rc 'at line' sigl '['errortext(rc)']')
  692.     rc                        = 0
  693. signal Exit
  694.  
  695.  
  696. Log: procedure Expose system.
  697.  
  698.     parse arg text, pre, level
  699.  
  700.     if ~datatype(level, 'N') then level = system.prg.loglevel
  701.  
  702.     tmp        = word('PRG MM', (pre~='')+1)
  703.     text    = system.tmp.logpre || pre' 'text
  704.  
  705.     MM_WriteLog 'text' level
  706. return
  707.  
  708.  
  709. Path: procedure
  710.  
  711.    parse arg path
  712.    if right(path,1) ~= '/' & right(path,1) ~= ':' then path = path'/'
  713. return path
  714.  
  715.  
  716. Parse_Args: procedure Expose system.
  717.  
  718.     parse arg args
  719.  
  720.     tpl        = system.cmdopts',?/S,'
  721.     args    = translate(args, '  ', '9'x)
  722.     p            = min(pos('/K', tpl), pos('/S', tpl))
  723.     p            = lastpos(',', left(tpl, p))
  724.     tpl        = substr(tpl, p+1) || left(tpl, max(p-1, 0))
  725.  
  726.     do while tpl~=''
  727.         parse var tpl template ',' tpl
  728.         parse var template keyword '/' .
  729.  
  730.         bool    = pos('/S',    template)>0
  731.         key        = pos('/K', template)>0
  732.         must    = pos('/A', template)>0
  733.         num        = pos('/N', template)>0
  734.  
  735.         select
  736.             when must then        system.arg.keyword    = '0'x
  737.             when bool    then        system.arg.keyword    = 0
  738.             when num    then        system.arg.keyword    = 0
  739.  
  740.             otherwise                    system.arg.keyword    = ''
  741.         end
  742.  
  743.         if bool | key    then    mode    = ~bool
  744.         else                                mode    = 2
  745.  
  746.         system.arg.keyword    = Get_Arg(keyword, mode, system.arg.keyword)
  747.  
  748.         if must & system.arg.keyword='0'x then
  749.             do
  750.                 tmp    = template 'missing!!!'
  751.  
  752.                 say
  753.                 say ' ***' tmp '***'
  754.  
  755.                 signal Usage
  756.             end
  757.  
  758.         if num & ~datatype(system.arg.keyword, 'N') then
  759.             do
  760.                 tmp    = 'Numeric value expected for' template', but is "'system.arg.keyword'"!!!'
  761.  
  762.                 say
  763.                 say ' ***' tmp '***'
  764.  
  765.                 signal Usage
  766.             end
  767.     end
  768.  
  769.     drop mode
  770.  
  771.     tmp    = '?'; if system.arg.tmp then signal Usage
  772.  
  773.     if args~='' then call Quit(10, 'Unknown option(s):' args)
  774.  
  775.     if system.arg.decode    then
  776.     if system.arg.encode | system.arg.area='' | system.arg.msg='' then signal Usage
  777.         else nop
  778.     else
  779.         do
  780.             upper system.arg.mode
  781.  
  782.             if ~system.arg.gui & system.arg.area=''                                            then signal Usage
  783.             if ~system.arg.gui & find('FS MIME UU', system.arg.mode)=0    then signal Usage
  784.  
  785.             if system.arg.infofile~=''    then
  786.                 do
  787.                     system.arg.infofile    = Expand_Path(system.arg.infofile)
  788.  
  789.                     if ~exists(system.arg.infofile)    then call Quit(11, system.arg.infofile 'does not exist!')
  790.                 end
  791.         end
  792.  
  793.     if system.arg.maxsize>0    then
  794.         if system.arg.maxsize<10000 then call Quit(11, 'Invalid value for MAXSIZE/K/N "'system.arg.maxsize'"!')
  795.         else
  796.             do
  797.                 tmp                                    = system.arg.mode
  798.                 system.tmp.maxsize    = system.arg.maxsize
  799.             end
  800.  
  801. return
  802.  
  803.  
  804. Quit:
  805.  
  806.     parse arg return_code, error_msg
  807.  
  808.     error_line    = 0
  809.     rc                        = 0
  810. signal Exit
  811.  
  812.  
  813. Read_Cfg: procedure Expose system.
  814.  
  815.     MM_ReadStem system.prg.cfg 'cfg'
  816.     if RC~=0 then call Quit(31, 'Unable to read' system.prg.cfg'!!!')
  817.  
  818.     call Log('Reading config...')
  819.  
  820.     cnt    = 0
  821.  
  822.     do l=0 to cfg.count-1
  823.         parse value strip(translate(cfg.l, ' ', '9'x)) with key args ';' .
  824.         key        = upper(strip(key))
  825.         args    = strip(args)
  826.  
  827.         select
  828.             when key='' then iterate
  829.  
  830.             when key='#FSDECODE'        then system.cmd.fs.decode        = args
  831.             when key='#FSENCODE'        then system.cmd.fs.encode        = args
  832.             when key='#FSMAXSIZE'        then
  833.                 if datatype(args, 'N') & args>=10000 then system.fs.maxsize    = args
  834.                 else call Quit(11, 'Invalid value "'args'" for #FSMAXSIZE at line' l'!')
  835.  
  836.             when key='#MIMEDECODE'    then system.cmd.mime.decode    = args
  837.             when key='#MIMEENCODE'    then system.cmd.mime.encode    = args
  838.             when key='#MIMEMAXSIZE'    then
  839.                 if datatype(args, 'N') & args>=10000 then system.mime.maxsize    = args
  840.                 else call Quit(11, 'Invalid value "'args'" for #MIMEMAXSIZE at line' l'!')
  841.  
  842.             when key='#UUDECODE'        then system.cmd.uu.decode        = args
  843.             when key='#UUENCODE'        then system.cmd.uu.encode        = args
  844.             when key='#UUMAXSIZE'        then
  845.                 if datatype(args, 'N') & args>=10000 then system.uu.maxsize    = args
  846.                 else call Quit(11, 'Invalid value "'args'" for #UUMAXSIZE at line' l'!')
  847.  
  848.             when key='#OUTDIR'            then system.prg.dir                    = path(args)
  849.  
  850.             otherwise say '*** CFG-ERROR: Unknown keword "'key'" at line' l'!!!'
  851.         end
  852.  
  853.         cnt    = cnt+1
  854.     end
  855.  
  856.     if cnt~=10    then    call Quit(10, 'Required config-argument(s) missing!')
  857.  
  858.     system.tmpdir        = system.prg.dir || system.prg.name'/'
  859.     system.tmpfile    = system.prg.dir || system.prg.name'.tmp'
  860.  
  861. return
  862.  
  863.  
  864. Read_Msg: procedure Expose msg. system.
  865.  
  866.     parse arg area, nr, errtxt
  867.  
  868.     call Log('Processing' area', msg #'nr'...',, 4)
  869.  
  870.     MM_ReadMsg area nr 'msg'
  871.     if RC~=0 then call Quit(20, errtxt)
  872.  
  873.     MM_AddToStem 'system.msg' 'nr'
  874.  
  875. return
  876.  
  877.  
  878. Replace: procedure
  879.  
  880.     parse arg string,new,old
  881.  
  882.     do while index(string, old)>0
  883.         interpret "parse var string l '"old"' r"
  884.         string = l || new || r
  885.     end
  886.  
  887. return string
  888.  
  889.  
  890. Request_Choice: procedure Expose system.
  891.  
  892.     parse arg text, buttons, ret_vals
  893.  
  894.     title    = system.prg.name'-Requester'
  895.     text    = translate(Replace(text, '0A'x, '\n'), '1b'x, '\')
  896.  
  897.     if length(text)<40 then text = center(text, 40)
  898.  
  899.     MM_Requester title 'text' 'buttons'
  900.  
  901.     if rc=0 then rc=words(ret_vals)
  902.  
  903. return compress(word(ret_vals, rc), '_')
  904.  
  905.  
  906. Request_String: procedure Expose RC system.
  907.  
  908.     parse arg txt, value, force
  909.  
  910.     old        = value
  911.  
  912.     do until ~force
  913.         MM_StringReq '"'txt'"' 'value'
  914.         if RC=1    then call Quit(5, 'Aborted by user!')
  915.  
  916.         value    = strip(value)
  917.         force = force & value=''
  918.     end
  919.  
  920. return value
  921.  
  922.  
  923. Search_Encoded: procedure Expose msg. result. system.
  924.  
  925.     arg type, id
  926.  
  927.     result.    = 0
  928.  
  929.     MM_SearchInStem 'msg.text' 'result' system.type.ptrn.id 'NUM'
  930.  
  931.     result.found    = ''
  932.  
  933.     do n=0 to result.count-1
  934.         result.found    = result.found result.n
  935.     end
  936.  
  937.     result.found    = strip(result.found)
  938.  
  939. return result.count>0
  940.  
  941.  
  942. Search_Encoded_Files: procedure Expose msg. system.
  943.  
  944.     parse arg area, msgnr
  945.  
  946.     call Read_Msg(area, msgnr, 'Could not access' area', msg #'nr'!')
  947.  
  948.     select
  949.         when Search_Encoded('UU', 'BEGIN')    then
  950.             do
  951.                 dest    = system.tmpdir
  952.                 mode    = 'UU'
  953.             end
  954.  
  955.         when Search_Encoded('FS', 'BEGIN')    then
  956.             do
  957.                 dest    = ''
  958.                 mode    = 'FS'
  959.             end
  960.  
  961.         when Search_Encoded('MIME', 'BEGIN')    then
  962.             do
  963.                 dest    = system.tmpdir
  964.                 mode    = 'MIME'
  965.             end
  966.  
  967.         otherwise call Quit(10, 'Could not locate UU-, FS- or MIME-encoded files!')
  968.      end
  969.  
  970.     system.cmd.mode.decode    = Replace(Replace(system.cmd.mode.decode, system.tmpfile, '%e'), dest, '%d')
  971.  
  972.     MM_GetAreaInfo area 'system.ainfo'
  973.  
  974.     encoded.            = ''
  975.   encoded.start    = result.found
  976.  
  977.     if system.arg.gui then
  978.         do
  979.             tmp.0.0    = ''
  980.             tmp.0.1    = 'it'
  981.             tmp.1.0    = 's'
  982.             tmp.1.1    = 'them'
  983.             tmp            = result.count>1
  984.  
  985.             ret = Request_Choice('\c\nThis msg contains' result.count mode'-encoded file'tmp.tmp.0'.\n\n' ||,
  986.                         'Shall I decode' tmp.tmp.1 'to' system.prg.dir'?\n', '* _YES |_Path|  _NO  ', '1 2 0')
  987.  
  988.             select
  989.                 when ret=0  then        call Quit(5, 'Aborted by user!')
  990.  
  991.                 when ret=2    then
  992.                     do
  993.                         MM_FileReq 'system.prg.dir'
  994.                         if RC~=0    then    call Quit(5, 'Aborted by user!')
  995.  
  996.                         p    = max(lastpos(':', system.prg.dir), lastpos('/', system.prg.dir))
  997.                         if p>0    then system.prg.dir = left(system.prg.dir, p)
  998.  
  999.                         if ~exists(system.prg.dir) then call Quit(31, system.prg.dir 'does not exist!')
  1000.                     end
  1001.  
  1002.                 otherwise nop
  1003.             end
  1004.         end
  1005.  
  1006.     call Log('Found' result.count mode'-encoded file(s).')
  1007.  
  1008.     line.    = -1
  1009.  
  1010.     do x=1 while encoded.start~=''
  1011.         parse var encoded.start line.start encoded.start
  1012.  
  1013.         call Search_Encoded(mode, 'END')
  1014.  
  1015.         do while line.ende<line.start & line.ende~=0
  1016.             parse var result.found line.ende result.found
  1017.  
  1018.             if ~datatype(line.ende, 'N') then line.ende=0
  1019.         end
  1020.  
  1021.         if line.ende=0    then    line.ende    = -1
  1022.  
  1023.         call Get_Encoded_File(mode, area, msgnr, line.start, line.ende, 1, system.mode.offs.begin)
  1024.         system.ok    = Decode_File(mode, system.tmpfile)=0
  1025.     end
  1026.  
  1027. return
  1028.  
  1029.  
  1030. Send_File: procedure Expose msg. system.
  1031.  
  1032.     arg mode
  1033.  
  1034.     call Log(mode'-encoding "'msg.send'"...')
  1035.  
  1036.   cmd    = Replace(Replace(system.cmd.mode.encode, msg.send, '%d'), system.tmpfile, '%e')
  1037.     ret    = Command(cmd)
  1038.  
  1039.     parse value statef(system.tmpfile) with . size .
  1040.  
  1041.     if ret>0 | ~datatype(size, 'N') then call Quit(20, 'Unable to' mode'-encode "'msg.send'"!')
  1042.  
  1043.     max    = (size%system.mode.maxsize)+1
  1044.  
  1045.     if max>1    then    msglen    = size%max
  1046.     else                        msglen    = system.mode.maxsize
  1047.  
  1048.     if system.arg.gui then
  1049.         if Request_Choice('\cShall I post\n\n\1'msg.send'\n(Encoded' size 'bytes =' max 'msgs)\0\n\nin area' msg.area'?',,
  1050.             '* _YES |  NO  ', '0 1') then call Quit(5, 'Posting aborted by user!')
  1051.  
  1052.     add                            = 1
  1053.     maxlen                    = length(max)
  1054.     msg.count                = 0
  1055.     msg.head.count    = 0
  1056.     msg.text.count    = 0
  1057.     msg.foot.count    = 0
  1058.     msg.tear                = system.prg.id
  1059.     subject                    = msg.subj
  1060.  
  1061.     if system.arg.infofile~=''    then
  1062.         do
  1063.             parse value statef(system.arg.infofile)'0 0' with . tmp .
  1064.  
  1065.             if tmp+size>system.mode.maxsize    then
  1066.                 do
  1067.                     add                = 0
  1068.                     msg.count    = -1
  1069.                     msg.file    = system.arg.infofile
  1070.  
  1071.                     call Write_Msg(0)
  1072.                 end
  1073.             else MM_ReadStem system.arg.infofile 'msg.text'
  1074.  
  1075.             if system.arg.delinfofile    then call delete(system.arg.infofile)
  1076.         end
  1077.  
  1078.     MM_ReadStem system.tmpfile 'uufile'
  1079.  
  1080.     msg.file            = system.tmpfile'2'
  1081.     cnt                        = 0
  1082.  
  1083.     if add then    call Add_Text()
  1084.  
  1085.     do n=0 to uufile.count-1
  1086.         cnt = cnt+length(uufile.n)+1
  1087.  
  1088.         if cnt>msglen then call Write_Msg(1)
  1089.  
  1090.         call Add_Text(uufile.n)
  1091.     end
  1092.  
  1093.     if msg.text.count>0    then call Write_Msg(1)
  1094.  
  1095.     if system.arg.gui        then call Request_Choice('\c\nFile successfully' mode'-encoded!.\n', '*  _OK  ', '0')
  1096.  
  1097.     call delete(system.tmpfile)
  1098.     call delete(msg.file)
  1099.  
  1100. return
  1101.  
  1102.  
  1103. Syntax:
  1104.     return_code        = 40
  1105.     error_line    = sigl
  1106.     error_msg            = 'Syntax-error' rc 'at line' sigl '['errortext(rc)']'
  1107.     rc                        = 0
  1108. signal Exit
  1109.  
  1110.  
  1111. Usage:
  1112.  
  1113.     rx.            = ''
  1114.     rx.0.0    = '[rx] '
  1115.     rx.0.1    = '[.rexx]'
  1116.     m                =    pos('/e', system.prg.ver)>0
  1117.     tmp            = rx.m.0 || system.prg.name || rx.m.1
  1118.  
  1119.     say
  1120.     say 'Usage:' tmp 'ENCODE/S/A,GUI/S,MODE/K/A,AREA/K,FILE/K,FLAGS/K,FROM/K,FROMADDR/K,ORIGIN/K,',
  1121.                                      'SUBJ/K,TO/K,TOADDR/K,INFOFILE/K,DELINFOFILE/S,MAXSIZE/K/N'
  1122.     say '   or:' tmp 'DECODE/S/A,GUI/S,AREA/A/K,MSG/A/K/N'
  1123.     say
  1124.  
  1125. call Quit(0, 'Usage requested.')
  1126.  
  1127.  
  1128. Write_Line: procedure Expose msg. system.
  1129.  
  1130.     parse arg nr, check
  1131.  
  1132.     if check then
  1133.         do
  1134.             tmp    = length(compress(msg.text.nr))
  1135.  
  1136.             if tmp~=length(msg.text.nr)    then return 0
  1137.             if tmp~=msg.enclen                    then return 0
  1138.         end
  1139.  
  1140.     call writeln(out, msg.text.nr)
  1141.  
  1142. return 1
  1143.  
  1144.  
  1145. Write_Msg:
  1146.  
  1147.     parse arg write
  1148.  
  1149.     msg.count    = msg.count+1
  1150.     msg.subj    = subject '['right(msg.count, maxlen, '0')'/'max']'
  1151.  
  1152.     call Add_Text()
  1153.     if system.is_mail then call Add_Text('---' system.prg.id'  'system.prg.cr)
  1154.  
  1155.     call Log('Posting' msg.subj 'in area' msg.area'...')
  1156.  
  1157.     if write then MM_WriteStem    msg.file 'msg.text'
  1158.  
  1159.     MM_WriteMsg        msg.area 'msg'
  1160.  
  1161.   cnt                         = 0
  1162.     msg.text.count    = 0
  1163.  
  1164.     call Add_Text()
  1165.  
  1166. return
  1167.  
  1168.  
  1169.